<template>
    <div v-if="connDialogVisible" id="dialog-conn">
        <span class="anhao">
            <span class="label">暗号</span>
            <span class="id">{{ peerId }}</span>
        </span>

        <div class="message">{{ connDialogMessage }}</div>
        <div>
            <el-button>取消</el-button>
        </div>
    </div>
    <div id="chat" v-else-if="!myPeerId"
        style="display: flex;justify-content: center;align-items: center;flex-direction: column;">
        <el-input v-model="peerId" @keydown.enter="confirmId" maxlength="8" style="width: 200px;margin-bottom: 15px;"
            placeholder="请输入暗号" autofocus></el-input>
        <div class="number-select">
            <div v-for="i in [7, 8, 9, 4, 5, 6, 1, 2, 3]" @click="addNumber(i)">
                {{ i }}
            </div>
            <div class="zero" @click="addNumber(0)">0</div>
            <div @click="peerId = peerId.slice(0, -1)">
                <svg t="1678598219959" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
                    p-id="2893" width="20" height="20">
                    <path
                        d="M484.46100645 627.90138495a28.76779355 28.76779355 0 0 1-20.34016344-49.107957l174.2671828-174.27268816a28.76779355 28.76779355 0 0 1 40.68473118 40.68032687l-174.2671828 174.27819355a28.6940215 28.6940215 0 0 1-20.34456774 8.42322581z"
                        fill="#1296db" p-id="2894"></path>
                    <path
                        d="M658.72708818 627.90138495a28.68301076 28.68301076 0 0 1-20.34016345-8.42322581l-174.26718279-174.27709248a28.76228818 28.76228818 0 0 1 0-40.68032687 28.75127742 28.75127742 0 0 1 40.68142795 0l174.2671828 174.27268816a28.77990537 28.77990537 0 0 1-20.34126451 49.107957z"
                        fill="#1296db" p-id="2895"></path>
                    <path
                        d="M834.5379785 821.18854194H340.57028818c-28.46940215 0-55.25305806-12.53684301-73.49016775-34.39428818L75.75838279 556.98112689c-10.54830108-13.06205592-16.20232258-28.91974194-16.1968172-44.98663226 0.00660645-15.39083011 4.67406452-29.85015053 13.50248602-41.81333334 0.33803011-0.45694624 0.68266666-0.90288172 1.04822366-1.33009892L266.70685592 237.63406452a95.32449032 95.32449032 0 0 1 73.86233118-34.82921291H834.5379785c51.98286452 0 94.27516559 42.28789677 94.27516558 94.27076129v429.83776344c0 51.98286452-42.29230108 94.27516559-94.27516558 94.2751656zM119.01522581 504.83420215c-0.90728602 1.35872689-1.91587097 3.52344086-1.91587097 7.17680861 0 2.92005161 1.14952258 6.01517419 3.15568172 8.50140214l191.02114409 229.45307528a38.55965592 38.55965592 0 0 0 29.29300645 13.69297203H834.5379785a36.78472258 36.78472258 0 0 0 36.74508387-36.74508387v-429.83776344a36.78472258 36.78472258 0 0 0-36.74508387-36.73957849H340.5691871a38.60590108 38.60590108 0 0 0-29.53524302 13.96934193L119.01522581 504.83420215z"
                        fill="#1296db" p-id="2896"></path>
                </svg>
            </div>
        </div>
        <el-checkbox v-model="useP2P">
            使用P2P
        </el-checkbox>
        <el-button @click="confirmId">确定ID</el-button>
    </div>
    <div id="chat" v-else>
        <div class="room">
            <div class="title">暗号:{{ peerId }}</div>
            <div v-if="peerConnected" class="latency">
                <el-tag>{{ latency }}ms</el-tag>
            </div>
            <div v-else class="latency">对方未连接</div>
        </div>
        <div class="contact">
            <div v-if="isVideoContract">
                <video id="local-video" width="300" autoplay></video>
                <video id="remote-video" width="300" autoplay></video>
            </div>
            <el-scrollbar v-else height="100%" ref="scrollbar">
                <div class="row" v-for="item in contacts">
                    <div v-if="item.type === 'system'" class="system">
                        <span>{{ item.message }}</span>
                    </div>
                    <div v-else-if="item.type === 'message'" :class="item.senderPeerId === myPeerId ? 'self' : 'peer'">
                        <span>{{ item.message }}</span>
                        <div class="status" :class="item.status">{{ item.statusStr }}</div>
                    </div>
                    <div v-else-if="item.type === 'image'" class="image"
                        :class="item.senderPeerId === myPeerId ? 'self' : 'peer'">
                        <el-image :src="item.message" fit="cover" :preview-src-list="imagePreviewList" preview-teleported
                            :alt="item.name"></el-image>
                    </div>
                    <div v-else-if="item.type === 'voice'" class="voice"
                        :class="item.senderPeerId === myPeerId ? 'self' : 'peer'">
                        <span>777777777秒</span>
                    </div>
                    <div v-else-if="item.type === 'file'" class="file"
                        :class="item.senderPeerId === myPeerId ? 'self' : 'peer'">
                        <div class="file-info">
                            <div class="name r">
                                <div class="k">文件名</div>
                                <div class="v">{{ item.name }}</div>
                            </div>
                            <div class="size r">
                                <div class="k">大小</div>
                                <div class="v">{{ formatBytes(item.size) }}</div>
                            </div>
                            <div class="jd r">
                                <div class="k">进度</div>
                                <div class="v">{{ item.jd.toFixed(2) }}%</div>
                            </div>
                            <template v-if="item.senderPeerId !== myPeerId">
                                <el-link v-if="item.state === 'ready'">合并中</el-link>
                                <el-link v-else-if="item.jd < 100">下载中</el-link>
                                <el-link v-else class="download" @click="downloadFile(item)">下载</el-link>
                            </template>
                            <template v-else>
                                <el-link v-if="item.state === 'reading'">读取中</el-link>
                                <el-link v-else-if="item.state === 'upload'">传输中</el-link>
                                <el-link v-else-if="item.state === 'uploaded'">已发送</el-link>
                            </template>
                        </div>
                    </div>
                </div>
            </el-scrollbar>
        </div>
        <div class="operate">
            <div class="input-box">
                <el-input v-model="message" @keydown.enter="send" autofocus></el-input>
                <el-button @click="send">发送</el-button>
            </div>
            <!-- <div class="emjoy other" title="选择表情">
                <svg t="1678545316465" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
                    p-id="4962" width="30" height="30">
                    <path
                        d="M942.577061 507.011382c0-237.637282-192.632275-430.269557-430.269557-430.269557s-430.269557 192.632275-430.269557 430.269557c0 237.647515 192.632275 430.27979 430.269557 430.27979 97.553827 0 186.878225-33.189913 259.055081-87.88563 2.964518-3.363607 4.91187-7.655354 4.91187-12.479219 0-10.531867-8.541537-19.073404-19.072381-19.073404-5.465478 0-10.334369 2.168386-13.808494 5.842055l-0.242524 0c-64.584947 47.526433-144.086629 75.981509-230.422973 75.981509-215.179804 0-389.645324-174.489056-389.645324-389.656581 0-215.201294 174.466544-389.644301 389.645324-389.644301 215.202317 0 389.645324 174.443008 389.645324 389.644301 0 65.738213-15.423271 127.60219-44.186362 181.922353l0 0.321318c-0.533143 1.814322-1.108241 3.583618-1.108241 5.53097 0 10.531867 8.541537 19.073404 19.073404 19.073404 8.207939 0 15.06716-5.265934 17.745153-12.523221l0 0.13303C924.544359 645.279493 942.577061 578.258053 942.577061 507.011382zM399.574976 391.378805c0-24.028253-19.47147-43.499723-43.500746-43.499723-24.029276 0-43.478234 19.47147-43.478234 43.499723 0 24.029276 19.448958 43.479257 43.478234 43.479257C380.102483 434.858062 399.574976 415.408081 399.574976 391.378805zM669.735999 347.945597c-24.004717 0-43.476187 19.448958-43.476187 43.478234 0 24.029276 19.47147 43.500746 43.476187 43.500746 24.029276 0 43.50177-19.47147 43.50177-43.500746C713.237769 367.394554 693.766298 347.945597 669.735999 347.945597zM702.196295 630.742405c0-11.793604-9.558703-21.330818-21.350261-21.330818-1.88186 0-3.562129 0.620124-5.335519 1.084705l-0.441045 0c-49.473785 22.723537-104.548124 38.610366-162.562423 38.610366-57.130162 0-111.007233-16.130376-159.907966-38.233789l-0.177032 0c-2.300392-0.818645-4.690836-1.461281-7.2798-1.461281-11.880585 0-21.505803 9.602705-21.505803 21.485337 0 8.120958 4.513804 15.222703 11.129478 18.872836 54.209646 24.6494 113.883747 42.980907 177.319521 42.980907 63.037708 0 124.240629-18.686594 178.185238-43.046399 0.308015-0.149403 0.217964-0.11154 0.070608-0.045025C696.59574 645.928269 702.196295 638.545114 702.196295 630.742405z"
                        fill="#1296db" p-id="4963"></path>
                </svg>
            </div> -->
            <div class="picture other" title="发送图片" @click="sendImage">
                <svg t="1678545426562" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
                    p-id="6023" width="30" height="30">
                    <path
                        d="M938.666667 553.92V768c0 64.8-52.533333 117.333333-117.333334 117.333333H202.666667c-64.8 0-117.333333-52.533333-117.333334-117.333333V256c0-64.8 52.533333-117.333333 117.333334-117.333333h618.666666c64.8 0 117.333333 52.533333 117.333334 117.333333v297.92z m-64-74.624V256a53.333333 53.333333 0 0 0-53.333334-53.333333H202.666667a53.333333 53.333333 0 0 0-53.333334 53.333333v344.48A290.090667 290.090667 0 0 1 192 597.333333a286.88 286.88 0 0 1 183.296 65.845334C427.029333 528.384 556.906667 437.333333 704 437.333333c65.706667 0 126.997333 16.778667 170.666667 41.962667z m0 82.24c-5.333333-8.32-21.130667-21.653333-43.648-32.917333C796.768 511.488 753.045333 501.333333 704 501.333333c-121.770667 0-229.130667 76.266667-270.432 188.693334-2.730667 7.445333-7.402667 20.32-13.994667 38.581333-7.68 21.301333-34.453333 28.106667-51.370666 13.056-16.437333-14.634667-28.554667-25.066667-36.138667-31.146667A222.890667 222.890667 0 0 0 192 661.333333c-14.464 0-28.725333 1.365333-42.666667 4.053334V768a53.333333 53.333333 0 0 0 53.333334 53.333333h618.666666a53.333333 53.333333 0 0 0 53.333334-53.333333V561.525333zM320 480a96 96 0 1 1 0-192 96 96 0 0 1 0 192z m0-64a32 32 0 1 0 0-64 32 32 0 0 0 0 64z"
                        fill="#1296db" p-id="6024"></path>
                </svg>
            </div>
            <div class="video other" title="发起视频" @click="callVideo">
                <svg t="1678545490444" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
                    p-id="7107" width="30" height="30">
                    <path
                        d="M768 648.533333V768H128V256h640v119.466667L896 298.666667v426.666666l-128-76.8z m0-93.866666l42.666667 25.6v-136.533334l-42.666667 25.6v85.333334zM213.333333 341.333333v341.333334h469.333334V341.333333H213.333333z"
                        fill="#1296db" p-id="7108"></path>
                </svg>
            </div>
            <div class="file other" title="发送文件" @click="sendFile">
                <svg t="1678545534112" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
                    p-id="8166" width="30" height="30">
                    <path
                        d="M736.005 696.494H174.18c-17.673 0-32-14.327-32-32V255.582c0-17.673 14.327-32 32-32h157.213c7.96 0 15.635 2.967 21.525 8.321l47.547 43.222h335.54c17.673 0 32 14.327 32 32v357.369c0 17.673-14.327 32-32 32z m-529.825-64h497.825V339.125H388.094a32.002 32.002 0 0 1-21.525-8.321l-47.547-43.222H206.18v344.912z"
                        fill="#1296db" p-id="8167"></path>
                    <path
                        d="M853.18 821.092H317.509c-17.673 0-32-14.327-32-32s14.327-32 32-32H821.18V414.206c0-17.673 14.327-32 32-32s32 14.327 32 32v374.886c0 17.673-14.327 32-32 32z"
                        fill="#1296db" p-id="8168"></path>
                </svg>
            </div>
        </div>
    </div>
</template>

<script>
import { Peer } from "peerjs";
import SocketPeer from "@/utils/socketpeer.js"
import config from '@/config/index'
import { blobToBase64URL, uuid, downloadFileByBlob, fileToBlob, formatBytes } from '@/utils/object.js'

//Peer实例
let peer
//与好友连接的实例（文字）
let conn
//媒体传输连接的实例（视频、音频）
let mediaConnection
//获取本地媒体设备的配置
const mediaConfig = {
    audio: true,
    video: {
        quality: 7,
        width: { ideal: 320 },
        height: { ideal: 240 }
    }
}

export default {
    data() {
        return {
            useP2P: false,
            //聊天内容
            contacts: [],
            //我的peerID
            myPeerId: "",
            //暗号
            peerId: "",
            //输入框的内容
            message: "",
            //好友的peerId
            otherPeerId: "",
            //一个标识
            gender: true,
            //预览图片用的
            imagePreviewList: [],
            //网络延迟
            latency: 0,
            //是否已和好友连接
            peerConnected: false,
            //是否显示等待页面
            connDialogVisible: false,
            //conn的ID
            connectionId: "",
            //等待页面的提示文字
            connDialogMessage: "",
            //当前是否为视频通话
            isVideoContract: false,
            chunk: {
                // 'chunkid':{
                //     chunks:[],
                //     total:1,
                //     metaInfo:{
                //         a:'',
                //         b:''
                //     }
                // },
            }
        }
    },
    methods: {
        formatBytes,
        //请求视频通话
        callVideo() {
            this.isVideoContract = true
            //通过这个api获取本地视频流，只有https协议下的网站有用
            navigator.mediaDevices.getUserMedia(mediaConfig)
                .then((localStream) => {
                    //打电话给好友
                    let call = peer.call(this.otherPeerId, localStream)
                    //处理与好友的通信
                    this.handleCallStream(call)
                    //将自己的视频流显示在标签中
                    const localVideo = document.getElementById('local-video');
                    localVideo.srcObject = localStream;
                    console.log("主动打电话,将本地视频流放在标签中", localVideo, localStream)
                })
                .catch((error) => {
                    console.log(`Error answering call: ${error}`);
                });
        },
        confirmId(state) {
            if (isNaN(this.peerId) || this.peerId.includes("-")) {
                return this.$message.warning("ID只能是数字")
            }
            if (this.peerId.length < 4 || this.peerId.length > 8) {
                return this.$message.warning("ID长度4~8位")
            }
            console.log("正在连接服务器")
            this.connDialogMessage = "正在连接服务器"
            //连接peer服务器

            if (this.useP2P) {
                peer = new Peer(this.peerId + "-" + this.gender, {
                    host: config.PEER_SERVER_HOST,
                    port: config.PEER_SERVER_PORT,
                    path: "/huat",
                    key: 'peerjs',
                    //通过iceServers可以提升通话质量
                    iceServers: [
                        { urls: 'stun:stun1.l.google.com:19302' },
                        { urls: 'stun:stun2.l.google.com:19302' },
                        { urls: 'stun:stun3.l.google.com:19302' },
                        { urls: 'stun:stun4.l.google.com:19302' }
                    ],
                    debug: 0
                })
            } else {
                peer = new SocketPeer(this.peerId + "-" + this.gender, {
                    host: config.SOCKET_PEER_SERVER_HOST,
                    port: config.SOCKET_PEER_SERVER_PORT,
                    secure: false,
                    path: "/huat",
                    key: 'peerjs',
                    secure:true
                })
            }
            //打开等待界面
            this.connDialogVisible = true

            //监听错误事件
            peer.on("error", e => {
                this.connDialogVisible = false
                if (e.type == 'unavailable-id') {
                    if (state === true) {
                        return this.$message.warning("此暗号正在被别人使用")
                    }
                    this.gender = !this.gender
                    this.confirmId(true)
                } else if (e.type == 'browser-incompatible') {
                    this.$message.error("浏览器不兼容WebRTC")
                } else if (e.type === 'peer-unavailable') {
                    this.tryConnectPeer()
                }
                else {
                    console.log(e.type)
                    console.log(e)
                    this.$message.error(e)
                }
            })
            peer.on("open", id => {
                console.log("我的Peer Id", id)
                this.receiveContact({
                    type: "system",
                    message: "连接服务器成功"
                })
                this.myPeerId = id
                this.connDialogMessage = "等待好友连接"
                // this.myPeerId = id
                // this.otherPeerId = this.peerId + "-" + !this.gender
                // this.initConn(peer.connect(this.otherPeerId))
                //false去连接true
                if (this.gender === false) {
                    this.tryConnectPeer()
                }
            })
            peer.on('connection', conn => {
                //true 监听被连接
                //false 主动去连接true
                // console.log("peerConnection")
                this.initConn(conn)
            });
            peer.on('disconnection', () => {
                this.receiveContact({
                    type: "system",
                    message: "与服务器断开连接，正在重连"
                })
                peer.reconnect()
            })
            peer.on('call', (call) => {
                this.isVideoContract = true
                // Answer the call and get the stream from the user's microphone and camera.
                navigator.mediaDevices.getUserMedia(mediaConfig)
                    .then((localStream) => {
                        // Answer the call with the user's stream.
                        call.answer(localStream);

                        // Handle the call stream.
                        const localVideo = document.getElementById('local-video');
                        localVideo.srcObject = localStream;
                        console.log("peerOnCall,将本地视频流放在标签中", localVideo, localStream)
                        this.handleCallStream(call);
                    })
                    .catch((error) => {
                        console.log(`Error answering call: ${error}`);
                    });
            });
        },
        onErrorCallback(e) {

        },
        //初始化conn，监听conn的事件
        initConn(con) {
            //如果连接相同，则不重复监听
            if (con.connectionId == this.connectionId) {
                return console.log("连接重复", this.connectionId)
            }
            conn = con
            conn.latencyTimer = () => {
                this.sendObj({
                    type: 'send_latency_1',
                    timestamp: new Date().getTime()
                })
            }
            conn.on("open", _ => {
                this.receiveContact({
                    type: "system",
                    message: "伙伴加入了聊天"
                })
                this.otherPeerId = conn.peer
                this.peerConnected = true
                this.connDialogVisible = false
                setTimeout(() => {
                    // conn.latencyTimer()
                }, 1000);
            })
            //监听data事件可以收到对方发的消息
            conn.on("data", data => {
                console.log("conn.onData")
                this.receiveContact(data)
            })
            conn.on("error", e => {
                console.log(e)
            })
            conn.on('close', () => {
                this.receiveContact({
                    type: "system",
                    message: "好友断开连接"
                })
                this.peerConnected = false
                if (this.gender === false) {
                    this.tryConnectPeer()
                }
            })
            peer.on('stream', function (stream) {
                console.log(stream)
            });
        },
        handleCallStream(call) {
            //监听好友的媒体流，将视频信息放在标签中
            call.on('stream', (remoteStream) => {
                console.log("onStream")
                const remoteVideo = document.getElementById('remote-video');
                remoteVideo.srcObject = remoteStream;
                console.log("callOnStream,将远程视频流放在标签中", remoteVideo, remoteStream)
            });

            // Handle call errors.
            call.on('error', (error) => {
                console.log(`Call error: ${error}`);
            });
        },
        tryConnectPeer() {
            setTimeout(() => {
                //只有当前的gender为false才会去连接好友
                if (this.gender === false) {
                    this.initConn(peer.connect(this.peerId + "-" + true))
                } else {
                    console.error("只有false能连接")
                }
            }, 1000);
        },
        send() {
            if (this.message === '') {
                return
            }
            window.jkldsjflk = window.jkldsjflk || 1
            let message = ({
                message: this.message,
                senderPeerId: this.myPeerId,
                type: "message",
                messageId: this.myPeerId + "-" + window.jkldsjflk++
            })
            this.sendObj(message)
            this.receiveContact(message)
            this.message = ''
        },
        sendImage() {
            //打开浏览文件对话框，获取选择的文件
            let inputObj = document.createElement('input')
            inputObj.setAttribute('type', 'file');
            inputObj.setAttribute("style", 'visibility:hidden');
            inputObj.setAttribute("multiple", "true")
            document.body.appendChild(inputObj);
            inputObj.click();
            inputObj.onchange = () => {
                let fileList = []
                for (let file of inputObj.files) {
                    fileList.push({
                        name: 'file.name',
                        image: file,
                        type: 'image',
                        size: file.size
                    })
                }
                document.body.removeChild(inputObj)
                //发送图片

                fileList.forEach(this.sendObj)
                fileList.forEach(this.receiveContact)
            }
        },
        sendFile() {
            //打开浏览文件对话框，获取选择的文件
            let inputObj = document.createElement('input')
            inputObj.setAttribute('type', 'file');
            inputObj.setAttribute("style", 'visibility:hidden');
            inputObj.setAttribute("multiple", "true")
            document.body.appendChild(inputObj);
            inputObj.click();
            inputObj.onchange = () => {
                for (let file of inputObj.files) {
                    let obj = {
                        file: file,
                        type: 'file',
                        state: 'reading'
                    }
                    this.receiveContact(obj).then(messageId=>{
                        this.sendfileByChunk(file, obj, messageId)
                    })
                }
                document.body.removeChild(inputObj)
            }
        },
        sendObj(message) {
            //console.log("发送消息", message)
            if (!conn) {
                throw new Error("conn未创建")
            } else if (conn.open) {
                //发送消息
                // setInterval(() => {
                //     console.log(conn.dataChannel.bufferedAmount)
                // }, 1);
                //console.log(conn)
                message.senderPeerId = this.myPeerId
                message.peerId = this.peerId
                conn.send(message);
            } else {
                //this.$message.warning("对方未连接")
                throw new Error("对方未连接")
            }
        },
        sendfileByChunk(file, obj, messageId) {
            let c = this.contacts.find(m => m.messageId == messageId)
            c.state = 'reading'
            const blob = new Blob([file], { type: file.type });
            c.state = 'upload'
            let chunkSize;
            if (this.useP2P) {
                chunkSize = 200 * 1024;
            } else {
                chunkSize = 2000 * 1024;
            }
            const totalChunks = Math.ceil(blob.size / chunkSize);
            let currentChunk = 0;
            const id = uuid()
            const uploadNextChunk = () => {
                const start = currentChunk * chunkSize;
                const end = Math.min(start + chunkSize, blob.size);
                const chunk = blob.slice(start, end);
                this.sendObj({
                    type: 'chunk',
                    chunk: chunk,
                    currentChunk: currentChunk,
                    id: id
                })
                //一个包发完了才能发下一个包
                currentChunk++
                if (currentChunk < totalChunks) {
                    uploadNextChunk();
                }
            }
            this.sendObj({
                type: 'chunkID',
                id,
                totalChunkCount: totalChunks,
                name: file.name,
                fileType: file.type,
                size: file.size
            })
            uploadNextChunk();
        },
        addNumber(n) {
            if (this.peerId.length >= 8) {
                return
            }
            this.peerId += n
        },
        sendReadMessage() {
            this.sendObj({
                senderPeerId: this.myPeerId,
                type: 'read',
                id: "pp"
            })
        },
        async receiveContact(message) {
            console.log("收到消息", message)
            if (message) {
                message.messageId = uuid()
                if (['system', 'message'].includes(message.type)) {
                    if (message.type === 'message') {
                        this.sendReadMessage()
                    }
                    this.contacts.push(message)
                } else if ('image' == message.type) {
                    let imageUrl = null
                    if (message.image instanceof ArrayBuffer) {
                        //ArrayBuffer转Blob，再转成base64URL
                        const blob = new Blob([message.image]);
                        imageUrl = URL.createObjectURL(blob);
                        this.contacts.push({
                            type: 'image',
                            name: message.name,
                            message: imageUrl,
                            messageId: message.messageId
                        })
                        this.sendReadMessage()
                    } else if (message.image instanceof File) {
                        //自己上传的文件，读取文件后转成base64URL
                        const file = message.image
                        const blob = new Blob([file], { type: file.type });
                        let url = await blobToBase64URL(blob)
                        imageUrl = url
                        this.contacts.push({
                            type: 'image',
                            name: file.name,
                            message: imageUrl,
                            senderPeerId: this.myPeerId,
                            messageId: message.messageId
                        })
                    }
                    if (imageUrl) {
                        this.imagePreviewList.push(imageUrl)
                    }

                } else if ('file' == message.type) {
                    if (message.file instanceof ArrayBuffer) {
                        console.error("不支持别人直接发文件")
                    } else if (message.file instanceof File) {
                        //自己上传的文件
                        const file = message.file
                        this.contacts.push({
                            type: 'file',
                            name: file.name,
                            file: file,
                            jd: 100,
                            size: file.size,
                            senderPeerId: this.myPeerId,
                            messageId: message.messageId
                        })
                    }
                } else if (message.type === 'read') {
                    console.log(message)
                } else if (message.type === 'send_latency_1') {
                    //send_latency_1和send_latency_2用于传输的延迟获取
                    message.type = 'send_latency_2'
                    this.sendObj(message)
                    //console.log("8888")
                } else if (message.type === 'send_latency_2') {
                    let now = new Date().getTime()
                    this.latency = now - message.timestamp
                    // console.log("网络延迟", this.latency)
                    setTimeout(() => {
                        conn.latencyTimer()
                    }, 3000);
                } else if (message.type === 'chunk') {
                    let id = message.id
                    let obj = this.initChunkInfo(id)
                    let contact = this.initContactInfo(id)
                    contact.messageId = message.messageId
                    if (this.useP2P) {
                        obj.chunks[message.currentChunk] = message.chunk
                    } else {
                        obj.chunks[message.currentChunk] = new Uint8Array(message.chunk).buffer
                    }
                    if (this.chunksAllReady(message, obj, contact)) {
                        //说明到了最后一个Chunk，开始合并这些
                        contact.jd = 100
                        contact.state = 'ready'
                        setTimeout(() => {
                            let blob
                            if (this.useP2P) {
                                blob = new Blob(obj.chunks)
                            } else {
                                blob = new Blob(obj.chunks)
                            }
                            contact.blob = blob
                            contact.state = 'ok'
                            console.log("文件传输完毕", contact, obj.chunks)
                        }, 10)
                    }
                } else if (message.type === 'chunkID') {
                    console.log(message)
                    let id = message.id
                    let obj = this.initChunkInfo(id)
                    obj.name = message.name
                    obj.totalChunkCount = message.totalChunkCount
                    obj.name = message.name
                    obj.fileType = message.type
                    obj.size = message.size
                    obj.senderPeerId = message.senderPeerId
                    let contact = this.initContactInfo(id)
                    contact.name = message.name
                    contact.size = message.size
                    contact.senderPeerId = obj.senderPeerId
                }
                else {
                    console.log("无法处理的message", message)
                }
                return message.messageId
            } else {
                console.log("message is false")
            }
        },
        chunksAllReady(message, obj, contact) {
            let readyChunks = 0
            obj.chunks.forEach(c => {
                if (c) {
                    readyChunks++
                }
            })
            if (readyChunks == obj.totalChunkCount) {
                return true
            } else {
                contact.jd = readyChunks * 100 / obj.totalChunkCount
            }
        },
        initContactInfo(id) {
            let contact = this.contacts.find(item => item.id === id)
            if (!contact) {
                contact = {
                    type: 'file',
                    id,
                    jd: 0
                }
                this.contacts.push(contact)
                return contact
            } else {
                return contact
            }
        },
        initChunkInfo(id) {
            if (!this.chunk[id]) {
                this.chunk[id] = {
                    id,
                    chunks: []
                }
            }
            return this.chunk[id]
        },
        downloadFile(item) {
            if (item.blob) {
                downloadFileByBlob(item.blob, item.name)
            } else if (item.file) {
                fileToBlob(item.file, blob => {
                    downloadFileByBlob(blob, item.name)
                })
            } else {
                console.error("不是期待的结果")
            }
        }
    },
    watch: {
        contacts: {
            handler(newValue, oldValue) {
                //监听contacts数组，如果当前滚动条在最下面，则进行滚动
                this.$nextTick(() => {
                    if (this.$refs.scrollbar) {
                        let el = this.$refs.scrollbar.wrap$.getElementsByClassName('el-scrollbar__view')[0]
                        // console.log(el)
                        let offsetHeight = el.offsetHeight
                        let scrollTop = this.$refs.scrollbar.wrap$.scrollTop
                        let elHeight = this.$refs.scrollbar.wrap$.offsetHeight
                        //获取最后一个元素的高度
                        let arr = el.getElementsByClassName("row")
                        let endElHeight = arr[arr.length - 1].offsetHeight
                        // console.log("endElHeight", endElHeight)

                        if (endElHeight + elHeight + scrollTop >= offsetHeight) {
                            //40是padding+margin
                            this.$refs.scrollbar.setScrollTop(scrollTop + endElHeight + 40)
                        }
                    }
                })
            },
            deep: true
        }
    }
};
</script>

<style lang="scss">
#chat {
    height: 100%;

    .number-select {
        display: flex;
        width: 180px;
        flex-wrap: wrap;
        margin-bottom: 15px;

        * {
            user-select: none;
        }

        div {
            width: 60px;
            height: 60px;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0px 0px 2px #ccc;
            cursor: pointer;
            transition: all .2s;

            &:hover {
                background-color: #ddd;
            }
        }

        .zero {
            width: 120px;
        }
    }

    .room {
        height: 50px;
        box-shadow: 0px 1px 1px #eee;
        display: flex;
        justify-content: center;
        gap: 15px;

        .title {
            font-weight: 700;
            font-size: 24px;
            text-align: center;
            line-height: 50px;
            display: flex;
            align-items: center;
            justify-content: center;

            span {
                white-space: nowrap;
            }

            .el-input {
                height: 25px;
            }
        }

        .latency {
            display: flex;
            align-items: center;
        }
    }

    .contact {
        display: flex;
        flex-direction: column;
        height: calc(100% - 50px - 80px);

        .row {
            padding: 10px;
            margin: 10px 0;

            .system {
                color: #999;
                text-align: center;
                font-size: 14px;
            }

            .self,
            .peer {
                display: flex;

                span {
                    display: inline-block;
                    padding: 10px;
                    max-width: 40%;
                    border-radius: 10px;
                    word-wrap: break-word;
                }

                .status {
                    font-size: 12px;
                    color: #ccc;
                    display: flex;
                    align-items: center;
                    margin: 0 10px;
                }

                .error {
                    color: #f00;
                }

                @media screen and (max-width: 992px) {
                    span {
                        max-width: 60%;
                    }
                }

                @media screen and (max-width: 400px) {
                    span {
                        max-width: 80%;
                    }
                }
            }

            .self {
                flex-direction: row-reverse;
            }

            .peer {
                flex-direction: row;
            }

            .peer span {
                background-color: #13d630;
            }

            .self span {
                background-color: #eee;
            }

            .self {
                text-align: right;

                span {
                    text-align: left;
                }
            }

            .image {
                .el-image {
                    width: 200px;
                    height: 100px;
                }
            }

            .file {
                .file-info {
                    box-shadow: 0px 0px 3px #ccc;
                    padding: 10px;

                    .r {
                        display: flex;
                        gap: 10px;

                        .k {
                            width: 60px;
                        }
                    }

                    span {
                        padding: 0;
                        max-width: unset;
                        background-color: unset;
                    }
                }
            }
        }
    }

    .operate {
        display: flex;
        align-items: center;
        justify-content: center;
        height: 70px;
        padding: 0 10px;
        margin-top: 10px;
        box-shadow: 0px -1px 1px #eee;

        .input-box {
            flex: 1;
            display: flex;
            align-items: center;
            margin-right: 10px;

            .el-input {
                margin-right: 10px;
            }
        }

        .other {
            margin-right: 10px;
            cursor: pointer;
            border-radius: 10px;
            display: flex;
            align-items: center;

            &:hover {
                background-color: #eee;

                svg path {
                    fill: #f00;
                }
            }
        }
    }
}

#dialog-conn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 50vh;
    gap: 20px;

    .anhao {
        display: flex;
        gap: 15px;
        align-items: center;

        .id {
            color: #000;
            font-size: 18px;
            font-weight: 600;
        }
    }
}
</style>
